import pymysql


def create_connection(host, port, user, password, db, charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor):
    """
    创建与MySQL数据库的连接。

    参数:
    - host (str): 数据库主机地址。
    - user (str): 数据库用户名。
    - password (str): 数据库密码。
    - db (str): 数据库名。
    - charset (str): 字符集，默认为'utf8mb4'。
    - cursorclass: 游标类，默认为pymysql.cursors.DictCursor。

    返回:
    - pymysql.connections.Connection: 数据库连接对象，如果连接失败则返回None。
    """
    try:
        conn = pymysql.connect(host=host, port=port, user=user, password=password, db=db, charset=charset,
                               cursorclass=cursorclass)
        return conn
    except pymysql.Error as e:
        print(f'数据库连接失败: {e}')
        return None


def execute_query(conn, query, params=None):
    """
    执行查询语句。

    参数:
    - conn (pymysql.connections.Connection): 数据库连接对象。
    - query (str): 查询语句。
    - params (tuple, optional): 查询参数，默认为None。

    返回:
    - list: 查询结果列表，如果查询失败则返回None。
    """
    try:
        with conn.cursor() as cursor:
            cursor.execute(query, params)
            return cursor.fetchall()
    except pymysql.Error as e:
        print(f'执行查询失败: {e}')
        return []


def execute_dml(conn, query, params=None):
    """
    执行数据操作语言(DML)语句，如INSERT、UPDATE或DELETE。

    参数:
    - conn (pymysql.connections.Connection): 数据库连接对象，用于执行SQL查询。
    - query (str): 要执行的SQL查询字符串。
    - params (tuple, optional): 可选参数，用于参数化查询，防止SQL注入。

    返回:
    - int: 返回受影响的行数，如成功插入、更新或删除的记录数。
    """
    try:
        # 使用上下文管理器自动处理cursor的关闭
        with conn.cursor() as cursor:
            # 执行参数化查询，提高安全性，防止SQL注入
            cursor.execute(query, params)
            # 提交事务，确保更改持久化
            conn.commit()
            # 返回受影响的行数
            return cursor.rowcount
    except pymysql.Error as e:
        # 捕获pymysql错误，打印错误信息并回滚事务
        print(f'执行DML失败: {e}')
        conn.rollback()
        # 返回0表示操作失败，无行受到影响
        return 0


def close_connection(conn):
    if conn:
        try:
            conn.close()
        except pymysql.Error as e:
            print(f"关闭数据库连接时出错: {e}")
